# 在users/serializers.py中创建序列化器对象
import email
import re

from django_redis import get_redis_connection
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings

from celery_tasks.email.tasks import send_verify_email
from users.models import User


class CreateUserSerializer(serializers.ModelSerializer):
    '''
    创建用户的序列化器
    '''
    # 这几个字段在用户表中没有 需要额外创建生成序列化器
    password2 = serializers.CharField(label='确认密码', write_only=True)
    sms_code = serializers.CharField(label='短信验证码', write_only=True)
    allow = serializers.BooleanField(label='同意协议', write_only=True)

    # 添加token字段 jwt 保存在token中 实现单点登陆 自动登陆
    token = serializers.CharField(label='登陆状态Token', read_only=True)

    class Meta:
        model = User
        # 把所有的字段加入序列化器中
        fields = ('id', 'username', 'password', 'password2', 'sms_code', 'allow', 'mobile', 'token')
        # 添加某些字段额外的校验参数 比如用户名的长度等
        extra_kwargs = {
            'username': {
                'min_length': 5,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许5-20个字符的用户名',
                    'max_length': '仅允许5-20个字符的用户名',
                }
            },
            'password': {
                'write_only': True,
                'min_length': 8,
                'max_length': 20,
                'error_messages': {
                    'min_length': '仅允许8-20个字符的密码',
                    'max_length': '仅允许8-20个字符的密码',
                }
            }

        }
        #  validate_mobile 校验单一字段的值 value
        # validate(self, attrs): 获取所有字段的所有的值

    # 手机号的验证  value 的意思是 拿到validate中mobile中的值
    def validate_mobile(self, value):
        '''验证手机号'''
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('手机号格式错误')
        return value

    # 检验用户是否同意协议
    def validate_allow(self, value):
        '''验证用户是否同意协议'''

        if not value:
            raise serializers.ValidationError('请同意用户协议')
        return value

    # 两次密码的判断
    def validate(self, attrs):
        ''' 密码二次确认'''

        if attrs['password'] != attrs['password2']:
            raise serializers.ValidationError('两次密码输入不一致')

        # 判断短信验证码是否正确 （判断用户输入的验证码和redis中储存的验证码是否一致）

        # 取得redis中验证码的对象（游标）
        redis_conn = get_redis_connection('sms_codes')

        # attrs['mobile'] 通过键mobile获取前端传过来的手机号对应的值
        # 这个mobile 是前端输入的手机号
        mobile = attrs['mobile']

        # 2. 在redis对象中，用前端传过来的手机号查询出redis保存改手机号对应的验证码
        real_sms_code = redis_conn.get('sms_%s'%mobile)

        # 3.
        if real_sms_code is None:
            raise serializers.ValidationError('无效的短信验证码')
        #  attrs['sms_code'] 获取前端输入的验证码  储存在redis中的验证码为二进制需要解码所以decode
        if attrs['sms_code'] != real_sms_code.decode():
            raise serializers.ValidationError('短信验证码错误')

        return attrs

    # 验证通过创建用户并保存在数据库中
    def create(self, validated_data):
        ''' 创建用户'''

        # django 的认证系统会加密密码  以下这几个字段 是在用户表中存在的
        user = User.objects.create_user(
            username=validated_data.get('username'),
            password=validated_data.get('password'),
            mobile=validated_data.get('mobile'),

        )

        # 实现自动登陆  服务器生成jwt 返回给客户端 浏览器储存jwt的方式有两种
        # localStorage - 永久数据存储;不同页面数据共享
        # - sessionStorage - 临时存储，关闭页面或浏览器数据会被清除;仅当前页面有效，不同页面数据不共享

        # 导包： from rest_framework_jwt.settings import api_settings
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        # jwt 头部内容 {'user_id': 12, 'email': '', 'username': '13600000000', 'exp': 1539048426}
        # payload载荷也是一个json,  json中的字段可以包括以下两部分:
        # 1. 官方声明的字段        iss (issuer)：签发人 exp (expiration time)：过期时间
        # 2.自定义的私有字段，比如，用户的相关信息或其他业务需要的必要信息(例如：user_id, user_name, email)

        # user：登录的用户对象
        payload = jwt_payload_handler(user)  # 生成payload, 得到字典

        token = jwt_encode_handler(payload)  # 生成jwt字符串

        # 生成jwt 通过序列化返回
        user.token = token
        return user


# 定义一个用户详情的序列的序列化器
class UserDrtailSerializer(serializers.ModelSerializer):
    '''用户详情的信息的序列化器'''

    class Meta(object):
        model = User
        fields = ('id', 'username', 'mobile', 'email', 'email_active')


# 定义一个email的序列化器（用于校验邮箱的正确性）
class EmailSerializer(serializers.ModelSerializer):
    '''
    修改用户邮箱的序列化器/
    '''

    class Meta:
        model = User
        fields = ('id', 'email')
        extra_kwargs = {
            'email': {
                'required':True
            }
        }

    def update(self, instance, validated_data):

        # 1. 校验用户邮箱

        # 2. 保存用户邮箱
        email = validated_data['email']
        print(type(email))
        instance.email = email
        print(type(instance.email))
        instance.save()

        # # 不通过
        # instance.email = validated_data['email']
        # print(type(instance.email))
        # instance.save()

        # 3. 生成邮箱激活连接
        verify_url = instance.generate_verify_email_url()
        print('verify_url', verify_url)

        # 4. 发送激活链接到用户邮箱
        send_verify_email.delay(email, verify_url)

        return instance
